import 'dart:math';
import 'package:flutter/cupertino.dart';

class AnimateView extends StatefulWidget {
  ///子Widget
  final Widget child;

  ///动画自定义
  final IAnimate? animate;

  ///是否需要执行动画
  final bool isNeedAnimate;

  ///是否需要每次刷新时都执行动画
  final bool isNeedFlashEveryTime;

  const AnimateView({
    super.key,
    required this.child,
    this.animate,
    this.isNeedFlashEveryTime = false,
    this.isNeedAnimate = true,
  });

  @override
  State<StatefulWidget> createState() => _AnimateViewState();
}

class _AnimateViewState extends State<AnimateView>
    with TickerProviderStateMixin {
  late IAnimate animate;
  late AnimationController controller;
  late Animation animation;
  bool isInitState = true;

  @override
  void initState() {
    super.initState();
    isInitState = true;
    animate = widget.animate ??
        TranslationAnimate(
            angle: TranslationAnimateDirection.rightToLeft.angle);
    animate.init();
    controller = animate.getAnimationController(this);
    animation = animate.getAnimation(controller, this);
    if (widget.isNeedAnimate) {
      //启动动画(正向执行)
      controller.forward();
    }
  }

  @override
  void didUpdateWidget(covariant AnimateView oldWidget) {
    super.didUpdateWidget(oldWidget);
    isInitState = false;
    if (widget.isNeedAnimate && widget.isNeedFlashEveryTime) {
      animate = widget.animate ??
          TranslationAnimate(
              angle: TranslationAnimateDirection.rightToLeft.angle);
      animate.init();
      controller = animate.getAnimationController(this);
      animation = animate.getAnimation(controller, this);
      //启动动画(正向执行)
      controller.forward();
    }
  }

  @override
  Widget build(BuildContext context) {
    return isInitState && widget.isNeedAnimate || widget.isNeedFlashEveryTime
        ? animate.animate(context, widget.child, animation, controller)
        : widget.child;
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

///动画抽象类。
///实现该类，定制自己的动画。
abstract class IAnimate {
  ///初始化
  void init();

  ///获取AnimationController
  AnimationController getAnimationController(TickerProvider provider);

  ///获取Animation
  Animation getAnimation(
      AnimationController controller, State<StatefulWidget> state);

  ///定制自己的动画，每一个item都会调用到animate，
  ///[widget] 执行动画之后的widget
  ///[index] 列表的item的index
  Widget animate(
    BuildContext context,
    Widget widget,
    Animation animation,
    AnimationController controller,
  );
}

///平移动画
class TranslationAnimate extends IAnimate {
  ///动画执行的总长度
  static double gap = 1000.0;

  ///动画执行角度
  final int angle;

  ///动画执行时长，毫秒(ms)
  final int duration;

  ///进入动画还是出去动画
  final TranslationAnimateType type;

  ///界面的宽，动画需要根据你需要操作的界面宽进行计算，不传代表屏幕宽
  final double? width;

  ///界面的高，动画需要根据你需要操作的界面高进行计算，不传代表屏幕高
  final double? height;

  ///动画状态回调
  final Function(AnimationStatus status)? callback;

  TranslationAnimate({
    this.angle = 0,
    this.duration = 500,
    this.type = TranslationAnimateType.translateIn,
    this.width,
    this.height,
    this.callback,
  });

  @override
  Widget animate(BuildContext context, Widget widget, Animation animation,
      AnimationController controller) {
    final size = MediaQuery.of(context).size;
    double width = this.width ?? size.width;
    double height = this.height ?? size.height;
    double left = 0;
    double top = 0;

    ///范围0.0->1000.0
    double animateValue = animation.value;
    int positiveAngle = angle;
    if (angle < 0) {
      int tempAngle = angle % 360;
      positiveAngle = 360 - tempAngle;
    }
    positiveAngle = positiveAngle % 360;

    ///范围0->1
    double rate = animateValue / gap;
    if (type == TranslationAnimateType.translateIn) {
      rate = rate - 1;
    }
    if (positiveAngle >= 0 && positiveAngle <= 45 ||
        positiveAngle >= 135 && positiveAngle <= 225 ||
        positiveAngle > 315 && positiveAngle <= 360) {
      ///移出距离以宽度为准
      left = rate * width;
      if (positiveAngle > 90 && positiveAngle < 270) {
        left = -left;
      }
      double tanValue = tan(positiveAngle * pi / 180);
      top = rate * width * tanValue;
    } else if (positiveAngle == 90) {
      top = rate * height;
      left = 0;
    } else if (positiveAngle == 270) {
      top = -rate * height;
      left = 0;
    } else {
      ///移出距离以高度为准
      top = rate * height;
      if (positiveAngle > 180 && positiveAngle < 360) {
        top = -top;
      }
      double tanValue = tan(positiveAngle * pi / 180);
      if (tanValue == 0) {
        left = 0;
      } else {
        left = rate * height / tanValue;
      }
    }

    //print("angle=$positiveAngle");
    //print("left=$left");
    //print("top=$top");

    return Container(
      transform: Matrix4.translationValues(left, top, 0),
      child: widget,
    );
  }

  @override
  Animation getAnimation(
      AnimationController controller, State<StatefulWidget> state) {
    return Tween(begin: 0.0, end: gap).animate(controller)
      ..addListener(() {
        if (state.mounted) {
          state.setState(() {});
        }
      })
      ..addStatusListener((status) {
        callback?.call(status);
      });
  }

  @override
  AnimationController getAnimationController(TickerProvider provider) {
    return AnimationController(
        duration: Duration(milliseconds: duration), vsync: provider);
  }

  @override
  void init() {}
}

///平移动画执行方向枚举
enum TranslationAnimateDirection {
  ///从下往上
  bottomToTop(90),

  ///从上往下
  topToBottom(270),

  ///从左往右
  leftToRight(0),

  ///从右往左
  rightToLeft(180);

  ///动画执行方向度数
  final int angle;

  const TranslationAnimateDirection(this.angle);
}

///位移动画类型
enum TranslationAnimateType {
  ///出去动画
  translateOut,

  ///进入动画
  translateIn
}
